﻿using NetMQ;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ParallelLib.Micro
{
    public class MicroService
    {
        private MyBus Bus;

        public string HostAddress { get; private set; }

        public string Name { get; private set; }

        public int Port { get; private set; }

        private NetMQActor Actor { get; set; }

        public MicroService(string name, int port)
        {
            Name = name;
            Port = port;
            mStopListenREvent = new ManualResetEvent(false);
        }

        public NodeKey GetNodeByIndex(int index)
        {
            if (index < 0 || index > Bus.Nodes.Count - 1)
                return null;
            int i = 0;
            foreach (var item in Bus.Nodes)
            {
                if (i == index)
                {
                    return item.Key;
                }
                i++;
            }
            return null;
        }

        public void Hello()
        {
            Bus.Publish("Hello From:" + this.Name);
        }

        public void InitNode()
        {
            Actor = MyBus.Create(Port, Name, out Bus);
            Actor.SendFrame(BusCmd.GetHostAddrCMD);
            var hostAddress = Actor.ReceiveFrameString();
            HostAddress = hostAddress;
        }

        public void PublishMsg(string prefix, string msg)
        {
            if (string.IsNullOrEmpty(msg))
                return;
            // publish a hello message
            // note we can use NetMQSocket send and receive extension methods
            Actor.SendMoreFrame(BusCmd.PublishCMD).SendMoreFrame(prefix).SendFrame(msg);
        }

        public void PublishMsg(string msg)
        {
            PublishMsg(BusCmd.PublishCMD, msg);
        }

        public void QueryAllNode()
        {
            if (Bus.Nodes == null || Bus.Nodes.Count == 0)
            {
                Console.WriteLine("Null Nodes.");
            }
            else
            {
                int i = 0;
                foreach (var item in Bus.Nodes)
                {
                    Console.WriteLine(i.ToString() + "--->" + item.Key.ToStringEx());
                    i++;
                }
            }
        }

        public void SayTo(NodeKey key, string msg)
        {
            Bus.SayTo(key, msg);
        }

        #region 集群消息

        private ManualResetEvent mStopListenREvent;

        private Thread mListener { get; set; }

        public event EventHandler<MsgArgs> OnReceivedMsg;

        public void StartListenMsg()
        {
            if (mListener == null)
                mListener = new Thread(new ThreadStart(ListenWork));
            if (mListener.ThreadState == ThreadState.Unstarted)
                mListener.Start();
            mStopListenREvent.Reset();
        }

        public void StopListenMsg()
        {
            mStopListenREvent.Set();
        }

        private void DoListen()
        {
            var actor = Actor;
            var hostAddress = HostAddress;
            string message = actor.ReceiveFrameString();
            switch (message)
            {
                case BusCmd.HelloCMD:
                    // another node is saying hello
                    var fromHostAddress = actor.ReceiveFrameString();
                    var msg = fromHostAddress + "说:你好?";
                    Console.WriteLine(msg);
                    // send back a welcome message via the Bus publisher
                    msg = hostAddress + "说:欢迎!";
                    actor.SendMoreFrame(BusCmd.PublishCMD).SendFrame(msg);
                    break;

                case BusCmd.AddNodeCMD:
                    var addedAddress = actor.ReceiveFrameString();
                    Console.WriteLine("总线添加节点：{0}。", addedAddress);
                    break;

                case BusCmd.DelNodeCMD:
                    var removedAddress = actor.ReceiveFrameString();
                    Console.WriteLine("总线移除节点：{0}。", removedAddress);
                    break;

                case BusCmd.RecvMsgCMD:
                    var msgs = new List<string>();
                    if (actor.TryReceiveMultipartStrings(TimeSpan.FromMilliseconds(200), System.Text.Encoding.UTF8, ref msgs))
                    {
                        int i = 0;
                        var builder = new StringBuilder();
                        while (msgs.Count > i)
                        {
                            builder.Append(msgs[i]);
                            Console.WriteLine("收到消息：{0}。", msgs[i]);
                            i++;
                        }
                        OnReceivedMsg?.BeginInvoke(this, new MsgArgs(builder.ToString()), null, null);
                    }
                    break;

                default:
                    // it's probably a welcome message
                    var msgs2 = new List<string>();
                    if (actor.TryReceiveMultipartStrings(TimeSpan.FromMilliseconds(200), System.Text.Encoding.UTF8, ref msgs2))
                    {
                        int i = 0;
                        while (msgs2.Count > i)
                        {
                            Console.WriteLine("其他消息：{0}。", msgs2[i]);
                            i++;
                        }
                    }
                    break;
            }
        }

        private void ListenWork()
        {
            while (true)
            {
                if (mStopListenREvent.WaitOne(0))
                    break;
                DoListen();
            }
        }

        #endregion 集群消息
    }

    public class MsgArgs : EventArgs
    {
        public string Data { get; private set; }

        public MsgArgs(string data)
        {
            Data = data;
        }
    }
}